#!/usr/bin/env perl

# AUTHORITY
# DATE
# DIST
# VERSION

use strict;
use warnings;

use Getopt::Long;

my %Opts = (
    tries => 0,
    waitretry => 10,
    exit_statuses => [
        split /\s*,\s*/,
        (defined $ENV{WGET_RETRY_EXIT_STATUSES} ?
             $ENV{WGET_RETRY_EXIT_STATUSES} : "1,3,4,5,6,7,8")],
);

my @ORIG_ARGV = @ARGV;
Getopt::Long::Configure(
    'bundling', 'pass_through', 'no_auto_abbrev', 'permute');
GetOptions(
    'help|h|?' => sub {
        print <<'_';
Usage: wget-retry [options] <url>...

Options:
  --help, -h, -?   Show this message and exit.
  --version        Show program version and exit.

All the other options will be passed to wget.

See manpage for more detailed documentation.
_
        exit 0;
    },
    'version' => sub {
        no warnings 'once';
        print "wget-retry version ", ($main::VERSION || "dev"),
            ($main::DATE ? " ($main::DATE)" : ""), "\n";
        exit 0;
    },

    'tries|t=i' => \$Opts{tries},
    'waitretry=i' => \$Opts{waitretry},
);

my $wget_cmd = $ENV{WGET_RETRY_WGET_CMD} || "wget";

my $retries = 0;
while (1) {
    system {$wget_cmd} $wget_cmd, @ORIG_ARGV;
    last unless $?;
    my $exit_code = $? >> 8;
    if (grep { $exit_code == $_ } @{ $Opts{exit_statuses} }) {
        $retries++;
        if ($Opts{tries} == 0 || $retries <= $Opts{tries}) {
            warn "wget-retry: $wget_cmd exit-code is $exit_code, retrying ($retries) after $Opts{waitretry} second(s) ...\n";
            sleep $Opts{waitretry};
            next;
        } else {
            warn "wget-retry: $wget_cmd exit-code is $exit_code, won't retry anymore, exiting\n";
            exit $exit_code;
        }
    } else {
        exit $exit_code;
    }
}

# ABSTRACT: Wget wrapper to retry harder
# PODNAME:

=head1 SYNOPSIS

Use like you would use B<wget>:

 % wget-retry -c -t0 https://example.com/url1 ...


=head1 DESCRIPTION

By default, B<wget> doesn't retry harder; only upon disconnection in the middle
of downloading (with C<-t>/C<--tries>, e.g. C<-t 0>) and on connection refused
(with C<--retry-connrefused>) but not on other network failures, e.g. DNS
resolution failure (which can happen sometimes).

This wrapper runs B<wget> then checks its exit code. If exit code indicates
network failure (4) it will re-run wget.

The number of tries is unlimited, or from the C<-t> (<--tries>) option. The
number of seconds to wait before each try is 10 seconds or from the
C<--waitretry> option.


=head1 OPTIONS

=head2 --help

Shortcuts: -h, -?.

=head2 --version


=head1 ENVIRONMENT

=head2 WGET_RETRY_EXIT_STATUSES

A comma-separated list of exit statuses to retry. For example, C<1,3,4,5,6,7,8>
means generic error (1), file I/O error (3), network failure (4), SSL
verification failure (5), username/password authentication failure (6), protocol
errors (7), as well as error response from server (8) will make wget-retry rerun
wget. The default is 1,3,4,5,6,7,8. For more details on wget exit statuses, see
the wget's manpage.

=head2 WGET_RETRY_WGET_CMD

String. Wget command to use. Defaults to C<wget>. Can be used to chain several
wrappers together.


=head1 SEE ALSO

B<wget>.
